/*
 *  Copyright (c) 1998, Regents of the University of California
 *  All rights reserved.
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *      * Redistributions of source code must retain the above copyright
 *        notice, this list of conditions and the following disclaimer.
 *      * Redistributions in binary form must reproduce the above copyright
 *        notice, this list of conditions and the following disclaimer in the
 *        documentation and/or other materials provided with the distribution.
 *      * Neither the name of the University of California, Berkeley nor the
 *        names of its contributors may be used to endorse or promote products
 *        derived from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
 *  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 *  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
 *  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 *  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package org.demis.dwarf.core.db.ddlreader;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.demis.dwarf.core.db.*;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.sql.Types;

/**
 * @version 1.0
 * @author <a href="mailto:demis27@demis27.net">Stéphane kermabon</a>
 */
public class DDLReader {

    private static final Logger logger = LoggerFactory.getLogger(DDLReader.class);

    public static Schema read(String filename) {
        SchemaStackHandler handler = new SchemaStackHandler();
        try {
            SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
            parser.parse(filename, handler);
        } catch (IOException ex) {
            logger.error(null, ex);
        } catch (ParserConfigurationException ex) {
            logger.error(null, ex);
        } catch (SAXException ex) { 
            logger.error(null, ex);
        }
        Schema schema = handler.getResult();

        processReferences(schema);

        return schema;
    }

    public static Schema read(InputStream inputStream) {
        SchemaStackHandler handler = new SchemaStackHandler();
        try {
            SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
            parser.parse(inputStream, handler);
        } catch (IOException ex) {
            logger.error(null, ex);
        } catch (ParserConfigurationException ex) {
            logger.error(null, ex);
        } catch (SAXException ex) {
            logger.error(null, ex);
        }
        Schema schema = handler.getResult();

        processReferences(schema);

        return schema;
    }

    public static Schema read(Reader reader) {
        SchemaStackHandler handler = new SchemaStackHandler();
        try {
            SAXParser parser = SAXParserFactory.newInstance().newSAXParser();

            parser.parse(new InputSource(reader), handler);
        } catch (IOException ex) {
            logger.error(null, ex);
        } catch (ParserConfigurationException ex) {
            logger.error(null, ex);
        } catch (SAXException ex) {
            logger.error(null, ex);
        }
        Schema schema = handler.getResult();

        processReferences(schema);

        return schema;
    }



    public static int getDataType(String dataType) {
        if (dataType.equals("array")) {
            return Types.ARRAY;
        }
        else if (dataType.equals("bigint")) {
            return Types.BIGINT;
        }
        else if (dataType.equals("binary")) {
            return Types.BINARY;
        }
        else if (dataType.equals("bit")) {
            return Types.BIT;
        }
        else if (dataType.equals("blob")) {
            return Types.BLOB;
        }
        else if (dataType.equals("char")) {
            return Types.CHAR;
        }
        else if (dataType.equals("clob")) {
            return Types.CLOB;
        }
        else if (dataType.equals("datalink")) {
            return Types.DATALINK;
        }
        else if (dataType.equals("date")) {
            return Types.DATE;
        }
        else if (dataType.equals("decimal")) {
            return Types.DECIMAL;
        }
        else if (dataType.equals("distinct")) {
            return Types.DISTINCT;
        }
        else if (dataType.equals("double")) {
            return Types.DOUBLE;
        }
        else if (dataType.equals("float")) {
            return Types.FLOAT;
        }
        else if (dataType.equals("integer")) {
            return Types.INTEGER;
        }
        else if (dataType.equals("java_object")) {
            return Types.JAVA_OBJECT;
        }
        else if (dataType.equals("longnvarchar")) {
            return Types.LONGNVARCHAR;
        }
        else if (dataType.equals("longvarbinary")) {
            return Types.LONGVARBINARY;
        }
        else if (dataType.equals("longvarchar")) {
            return Types.LONGVARCHAR;
        }
        else if (dataType.equals("nchar")) {
            return Types.NCHAR;
        }
        else if (dataType.equals("nclob")) {
            return Types.NCLOB;
        }
        else if (dataType.equals("numeric")) {
            return Types.NUMERIC;
        }
        else if (dataType.equals("nvarchar")) {
            return Types.NVARCHAR;
        }
        else if (dataType.equals("real")) {
            return Types.REAL;
        }
        else if (dataType.equals("ref")) {
            return Types.REF;
        }
        else if (dataType.equals("rowid")) {
            return Types.ROWID;
        }
        else if (dataType.equals("smallint")) {
            return Types.SMALLINT;
        }
        else if (dataType.equals("sqlxml")) {
            return Types.SQLXML;
        }
        else if (dataType.equals("struct")) {
            return Types.STRUCT;
        }
        else if (dataType.equals("time")) {
            return Types.TIME;
        }
        else if (dataType.equals("timestamp")) {
            return Types.TIMESTAMP;
        }
        else if (dataType.equals("tinyint")) {
            return Types.TINYINT;
        }
        else if (dataType.equals("varbinary")) {
            return Types.VARBINARY;
        }
        else if (dataType.equals("varchar")) {
            return Types.VARCHAR;
        }
        else {
            return -1;
        }
    }

    private static void processReferences(Schema schema) {
        for (Table table : schema.getTables()) {
            for (Index index : table.getIndexes()) {
                for (ColumnReference columnReference: index.getColumnReferences()) {
                    columnReference.setColumn(table.getColumn(columnReference.getColumnName()));
                }
            }
            if (table.getPrimaryKey() != null) {
                for (ColumnReference columnReference: table.getPrimaryKey().getColumnReferences()) {
                    columnReference.setColumn(table.getColumn(columnReference.getColumnName()));
                    columnReference.getColumn().setPrimaryKey(true);
                }
            }
            for (ForeignKey foreignKey: table.getImportedKeys()) {
                foreignKey.setExportedTable(schema.getTable(foreignKey.getExportedTableName()));
                foreignKey.setImportedTable(table);

                for (ColumnReference columnReference: foreignKey.getExportedColumnReferences()) {
                    columnReference.setColumn(foreignKey.getExportedTable().getColumn(columnReference.getColumnName()));
                    foreignKey.getExportedTable().getColumn(columnReference.getColumnName()).setNoref(false);
                }
                for (ColumnReference columnReference: foreignKey.getImportedColumnReferences()) {
                    columnReference.setColumn(foreignKey.getImportedTable().getColumn(columnReference.getColumnName()));
                    foreignKey.getImportedTable().getColumn(columnReference.getColumnName()).setNoref(false);
                }
            }
        }
    }

}
